home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / copytape.lha / copytape / copytape.c < prev    next >
C/C++ Source or Header  |  1990-01-09  |  7KB  |  302 lines

  1.  
  2. /*
  3.  * COPYTAPE.C
  4.  *
  5.  * This program duplicates magnetic tapes, preserving the
  6.  * blocking structure and placement of tape marks.
  7.  *
  8.  * This program was updated at
  9.  *
  10.  *    U.S. Army Artificial Intelligence Center
  11.  *    HQDA (Attn: DACS-DMA)
  12.  *    Pentagon
  13.  *    Washington, DC  20310-0200
  14.  *
  15.  *    Phone: (202) 694-6900
  16.  *
  17.  **************************************************
  18.  *
  19.  *    THIS PROGRAM IS IN THE PUBLIC DOMAIN
  20.  *
  21.  **************************************************
  22.  *
  23.  * July 1986        David S. Hayes
  24.  *        Made data file format human-readable.
  25.  *
  26.  * April 1985        David S. Hayes
  27.  *        Original Version.
  28.  */
  29.  
  30.  
  31. #include <stdio.h>
  32. #include <sys/types.h>
  33. #include <sys/ioctl.h>
  34. #include <sys/mtio.h>
  35. #include <sys/file.h>
  36.  
  37. extern int      errno;
  38.  
  39. #define BUFLEN        262144    /* max tape block size */
  40. #define TAPE_MARK    -100    /* return record length if we read a
  41.                  * tape mark */
  42. #define END_OF_TAPE    -101    /* 2 consecutive tape marks */
  43. #define FORMAT_ERROR    -102    /* data file munged */
  44.  
  45. int             totape = 0,    /* treat destination as a tape drive */
  46.                 fromtape = 0;    /* treat source as a tape drive */
  47.  
  48. int             verbose = 0;    /* tell what we're up to */
  49.  
  50. char           *source = "stdin",
  51.                *dest = "stdout";
  52.  
  53. char            tapebuf[BUFLEN];
  54.  
  55. main(argc, argv)
  56.     int             argc;
  57.     char           *argv[];
  58. {
  59.     int             from = 0,
  60.                     to = 1;
  61.     int             len;    /* number of bytes in record */
  62.     int             skip = 0;    /* number of files to skip before
  63.                  * copying */
  64.     unsigned int    limit = 0xffffffff;
  65.     int             i;
  66.     struct mtget    status;
  67.  
  68.     for (i = 1; i < argc && argv[i][0] == '-'; i++) {
  69.     switch (argv[i][1]) {
  70.       case 's':        /* skip option */
  71.         skip = atoi(&argv[i][2]);
  72.         break;
  73.  
  74.       case 'l':
  75.         limit = atoi(&argv[i][2]);
  76.         break;
  77.  
  78.       case 'f':        /* from tape option */
  79.         fromtape = 1;
  80.         break;
  81.  
  82.       case 't':        /* to tape option */
  83.         totape = 1;
  84.         break;
  85.  
  86.       case 'v':        /* be wordy */
  87.         verbose = 1;
  88.         break;
  89.  
  90.       default:
  91.         fprintf(stderr, "usage: copytape [-f] [-t] [-lnn] [-snn] [-v] from to\n");
  92.         exit(-1);
  93.     }
  94.     }
  95.  
  96.     if (i < argc) {
  97.     from = open(argv[i], O_RDONLY);
  98.     source = argv[i];
  99.     if (from == -1) {
  100.         perror("copytape: input open failed");
  101.         exit(-1);
  102.     }
  103.     i++;;
  104.     }
  105.     if (i < argc) {
  106.     to = open(argv[i], O_WRONLY | O_CREAT | O_TRUNC, 0666);
  107.     dest = argv[i];
  108.     if (to == -1) {
  109.         perror("copytape: output open failed");
  110.         exit(-1);
  111.     }
  112.     i++;
  113.     }
  114.     if (i < argc)
  115.     perror("copytape: extra arguments ignored");
  116.  
  117.     /*
  118.      * Determine if source and/or destination is a tape device. Try to
  119.      * issue a magtape ioctl to it.  If it doesn't error, then it was a
  120.      * magtape. 
  121.      */
  122.  
  123.     errno = 0;
  124.     ioctl(from, MTIOCGET, &status);
  125.     fromtape |= errno == 0;
  126.     errno = 0;
  127.     ioctl(to, MTIOCGET, &status);
  128.     totape |= errno == 0;
  129.     errno = 0;
  130.  
  131.     if (verbose) {
  132.     fprintf(stderr, "copytape: from %s (%s)\n",
  133.         source, fromtape ? "tape" : "data");
  134.     fprintf(stderr, "          to %s (%s)\n",
  135.         dest, totape ? "tape" : "data");
  136.     }
  137.  
  138.     /*
  139.      * Skip number of files, specified by -snnn, given on the command
  140.      * line. This is used to copy second and subsequent files on the
  141.      * tape. 
  142.      */
  143.  
  144.     if (verbose && skip) {
  145.     fprintf(stderr, "copytape: skipping %d input files\n", skip);
  146.     }
  147.     for (i = 0; i < skip; i++) {
  148.     do {
  149.         len = input(from);
  150.     } while (len > 0);
  151.     if (len == FORMAT_ERROR) {
  152.         perror(stderr, "copytape: format error on skip");
  153.         exit(-1);
  154.     };
  155.     if (len == END_OF_TAPE) {
  156.         fprintf(stderr, "copytape: only %d files in input\n", i);
  157.         exit(-1);
  158.     };
  159.     };
  160.  
  161.     /*
  162.      * Do the copy. 
  163.      */
  164.  
  165.     len = 0;
  166.     while (limit && !(len == END_OF_TAPE || len == FORMAT_ERROR)) {
  167.     do {
  168.         do {
  169.         len = input(from);
  170.         if (len == FORMAT_ERROR)
  171.             perror("copytape: data format error - block ignored");
  172.         } while (len == FORMAT_ERROR);
  173.  
  174.         output(to, len);
  175.  
  176.         if (verbose) {
  177.         switch (len) {
  178.           case TAPE_MARK:
  179.             fprintf(stderr, "  copied MRK\n");
  180.             break;
  181.  
  182.           case END_OF_TAPE:
  183.             fprintf(stderr, "  copied EOT\n");
  184.             break;
  185.  
  186.           default:
  187.             fprintf(stderr, "  copied %d bytes\n", len);
  188.         };
  189.         };
  190.     } while (len > 0);
  191.     limit--;
  192.     }
  193.     exit(0);
  194. }
  195.  
  196.  
  197. /*
  198.  * Input up to 256K from a file or tape. If input file is a tape, then
  199.  * do markcount stuff.  Input record length will be supplied by the
  200.  * operating system. 
  201.  */
  202.  
  203. input(fd)
  204.     int             fd;
  205. {
  206.     static          markcount = 0;    /* number of consecutive tape
  207.                      * marks */
  208.     int             len,
  209.                     l2,
  210.                     c;
  211.     char            header[40];
  212.  
  213.     if (fromtape) {
  214.     len = read(fd, tapebuf, BUFLEN);
  215.     switch (len) {
  216.       case -1:
  217.         perror("copytape: can't read input");
  218.         return END_OF_TAPE;
  219.  
  220.       case 0:
  221.         if (++markcount == 2)
  222.         return END_OF_TAPE;
  223.         else
  224.         return TAPE_MARK;
  225.  
  226.       default:
  227.         markcount = 0;        /* reset tape mark count */
  228.         return len;
  229.     };
  230.     }
  231.     /* Input is really a data file. */
  232.     l2 = read(fd, header, 5);
  233.     if (l2 != 5 || strncmp(header, "CPTP:", 5) != 0)
  234.     return FORMAT_ERROR;
  235.  
  236.     l2 = read(fd, header, 4);
  237.     if (strncmp(header, "BLK ", 4) == 0) {
  238.     l2 = read(fd, header, 7);
  239.     if (l2 != 7)
  240.         return FORMAT_ERROR;
  241.     header[6] = '\0';
  242.     len = atoi(header);
  243.     l2 = read(fd, tapebuf, len);
  244.     if (l2 != len)
  245.         return FORMAT_ERROR;
  246.     read(fd, header, 1);    /* skip trailing newline */
  247.     } else if (strncmp(header, "MRK\n", 4) == 0)
  248.     return TAPE_MARK;
  249.     else if (strncmp(header, "EOT\n", 4) == 0)
  250.     return END_OF_TAPE;
  251.     else
  252.     return FORMAT_ERROR;
  253.  
  254.     return len;
  255. }
  256.  
  257.  
  258. /*
  259.  * Copy a buffer out to a file or tape. 
  260.  *
  261.  * If output is a tape, write the record.  A length of zero indicates that
  262.  * a tapemark should be written. 
  263.  *
  264.  * If not a tape, write len to the output file, then the buffer.  
  265.  */
  266.  
  267. output(fd, len)
  268.     int             fd,
  269.                     len;
  270. {
  271.     struct mtop     op;
  272.     char            header[20];
  273.  
  274.     if (totape && (len == TAPE_MARK || len == END_OF_TAPE)) {
  275.     op.mt_op = MTWEOF;
  276.     op.mt_count = 1;
  277.     ioctl(fd, MTIOCTOP, &op);
  278.     return;
  279.     }
  280.     if (!totape) {
  281.     switch (len) {
  282.       case TAPE_MARK:
  283.         write(fd, "CPTP:MRK\n", 9);
  284.         break;
  285.  
  286.       case END_OF_TAPE:
  287.         write(fd, "CPTP:EOT\n", 9);
  288.         break;
  289.  
  290.       case FORMAT_ERROR:
  291.         break;
  292.  
  293.       default:
  294.         sprintf(header, "CPTP:BLK %06d\n", len);
  295.         write(fd, header, strlen(header));
  296.         write(fd, tapebuf, len);
  297.         write(fd, "\n", 1);
  298.     }
  299.     } else
  300.     write(fd, tapebuf, len);
  301. }
  302.